home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / console / svgatext.3 / svgatext / SVGATextMode-1.3 / vga_prg.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-18  |  13.7 KB  |  462 lines

  1. /*  SVGATextMode -- An SVGA textmode manipulation/enhancement tool
  2.  *
  3.  *  Copyright (C) 1995,1996  Koen Gadeyne
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License
  16.  *  along with this program; if not, write to the Free Software
  17.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  */
  19.  
  20.  
  21. /***
  22.  *** VGA chip programming functions for SVGATextMode
  23.  ***/
  24.  
  25. #include <stdio.h>
  26. #include <stdarg.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <unistd.h>
  30. #include "misc.h"
  31. #include "vga_prg.h"
  32. #include "messages.h"  
  33.  
  34. /*
  35.  * global vars
  36.  */
  37.  
  38.  int vgaIOBase  = 0x3D0; /* default = color */
  39.  int vgaCRIndex = 0x3D4;
  40.  int vgaCRReg   = 0x3D5;
  41.  bool vga_open   = FALSE;
  42.  
  43. /*
  44.  * Some functions to make life easier (?!)
  45.  */
  46.  
  47. void Outb_ATR_CTL (int index, int data)
  48. {
  49.   inb(ATR_CTL_INDEX_DATA_SWITCH);
  50.   outb (index & 0x1f, ATR_CTL_INDEX);
  51.   outb ( data, ATR_CTL_DATA_W);
  52.   inb(ATR_CTL_INDEX_DATA_SWITCH);
  53.   outb ( (index & 0x1f) | 0x20, ATR_CTL_INDEX);
  54.   outb ( data, ATR_CTL_DATA_W);
  55. }
  56.  
  57. int inb_ATR_CTL (int index)
  58. {
  59.   int res;
  60.  
  61.   inb(ATR_CTL_INDEX_DATA_SWITCH);
  62.   outb (index & 0x1f, ATR_CTL_INDEX);
  63.   res=inb(ATR_CTL_DATA_R);
  64.   inb(ATR_CTL_INDEX_DATA_SWITCH);
  65.   outb ( (index & 0x1f) | 0x20, ATR_CTL_INDEX);
  66.   inb(ATR_CTL_DATA_R);
  67.   return res;
  68. }
  69.  
  70.  
  71. /*****************************************************************************************************************************/
  72.  
  73. void get_IO_range(int start, int len)
  74. {
  75.   PDEBUG(("Getting VGA IO permissions for addr. range 0x%x-0x%x\n", start, start+len-1));
  76.   if (ioperm(start, len, 1) != 0)
  77.   {
  78.     perror("VGA I/O Permissions");
  79.     PERROR(("Cannot get I/O permissions for hardware address range 0x%x-0x%x.\n\
  80.              You must be superuser, or the program must be setuid root!\n", start, start+len-1));
  81.   }
  82. }
  83.  
  84. /*
  85.  * Get IO permissions, and setup some global variables for VGA programming.
  86.  */
  87.  
  88. void get_VGA_io_perm(int chipset)
  89. {
  90.   PDEBUG(("Getting VGA IO permissions for chipset #%d\n", chipset));
  91.   vga_open=FALSE;
  92.   get_IO_range(0x3b4, 0x3df - 0x3b4 + 1);
  93.   switch(chipset)
  94.   {
  95.     case CS_ATI:
  96.     case CS_ATIMACH32:  get_IO_range(ATI_EXTREG, 2);
  97.                         break;
  98.     case CS_S3:  get_IO_range(0x200, 2);   /* used by ICD2061 clock code for IOdelay */
  99.  
  100.   }
  101.   
  102. #ifdef RUN_SECURE
  103.   Renounce_SUID; /* if we are Setuid Root: renounce to further superuser rights (safer) */
  104. #endif
  105.  
  106.   vga_open=TRUE;  /* needed for PERROR, so it knows if it can restore the screen or not */
  107.  
  108.   /* this is probably not the best place to put this */
  109.   vgaIOBase  = GET_VGA_BASE;
  110.   vgaCRIndex = (vgaIOBase+4);
  111.   vgaCRReg   = (vgaIOBase+5);
  112.   
  113.  
  114. }
  115.  
  116. /*****************************************************************************************************************************/
  117.  
  118. void unlock(int chipset)
  119. {
  120.    /* unlock ALL locked registers for specified chipset. A bit rough, but simplest */
  121.    PDEBUG(("Unlocking chipset %d\n",chipset));
  122.    Outbit_CRTC (0x11, 7, 0); /* CRTC index 0x00..0x07 */
  123.    switch(chipset)
  124.    {
  125.     case CS_CIRRUS :
  126.        Outb_SEQ (0x6, 0x12);    /* unlock cirrus special */
  127.        break;
  128.     case CS_S3     : 
  129.        Outb_CRTC(0x39, 0xa5); /* system extension regs (CRTC index 0x50..0x5E) */
  130.        Outb_CRTC(0x38, 0x48); /* S3 register set (CRTC index 0x30..0x3C) */
  131.        Outbit_CRTC(0x35, 4, 0); /* VERT timing regs (CRTC index 6,7(bit0,2,3,5,7),9,10,11(bits0..3),15,16 ) */
  132.        Outbit_CRTC(0x35, 5, 0); /* HOR timing regs (CRTC index 0..5, 17(bit2) ) */
  133.        Outbit_CRTC(0x34, 5, 0); /* bit 0 of Clocking mode reg unlocked (8/9 dot font selection) */
  134.        Outbit_CRTC(0x34, 7, 0); /* Clock bits in MISC reg unlocked */
  135.       /*  Outbit_CRTC(0x40, 0, 1); */ /* enhanced register access, only for access to accelerator commands. Does NOT seem to work on my 805 */
  136.        break;
  137.     case CS_ET4000 :
  138.     case CS_ET3000 :
  139.        outb(0x03, 0x3BF); outb(0xA0, 0x3D8); /* ET4000W32i key */
  140.        break;
  141.     case CS_ATI:
  142.     case CS_ATIMACH32:
  143.        ATI_PUTEXTREG(0xB4, ATI_GETEXTREG(0xB4) & 0x03);
  144.        ATI_PUTEXTREG(0xB8, ATI_GETEXTREG(0xb8) & 0xC0);
  145.        ATI_PUTEXTREG(0xB9, ATI_GETEXTREG(0xb9) & 0x7F);
  146.        ATI_PUTEXTREG(0xBE, ATI_GETEXTREG(0xbe) | 0x01);
  147.        break;
  148.     case CS_PVGA1:
  149.     case CS_WDC90C0X:
  150.     case CS_WDC90C1X:
  151.     case CS_WDC90C2X:
  152.     case CS_WDC90C3X:
  153.        Outb_GR_CTL(0x0F, (Inb_GR_CTL(0x0F) & 0x80) | 0x05);
  154.        if (chipset != CS_PVGA1)    /* these might not be needed */
  155.        {
  156.          Outb_CRTC(0x29, (Inb_CRTC(0x29) & 0x70) | 0x85);
  157.          Outb_CRTC(0x2a, Inb_CRTC(0x2a) & 0xF8);
  158.          if (chipset != CS_WDC90C0X)
  159.          {
  160.            Outb_SEQ(0x06, 0x48);
  161.            if (chipset != CS_WDC90C1X) Outb_CRTC(0x34, 0xA6);
  162.          }
  163.        }
  164.        break;
  165.     case CS_ALI:
  166.     case CS_AL2101:
  167.        Outbit_CRTC(0x1A, 4, 1);
  168.        break; 
  169.     case CS_OTI67:
  170.     case CS_OTI77:  /* CS_OTI87 doesn't seem to need unlocking */
  171.        Outb_OTI( OTI_CRT_CNTL, Inb_OTI(OTI_CRT_CNTL) & 0xF0 );
  172.        break; 
  173.     case CS_SIS:
  174.        Outb_SEQ(0x05, 0x86);
  175.        break;
  176.     case CS_ARK:
  177.        Outbit_SEQ(0x1D, 0, 1); 
  178.        break;
  179.     case CS_NCR22E:
  180.     case CS_NCR32:
  181.        Outbit_SEQ(0x05, 0, 1);
  182.        break;
  183.     case CS_MX:
  184.        Outbit_SEQ(0x65, 6, 1); /* not in XFree86, but VGADOC4 says otherwise */
  185.        Outb_SEQ(0xA7, 0x87);
  186.        break;
  187.     default: PDEBUG(("UNLOCK VGA: No special register unlocking needed for chipset #%d\n",chipset));
  188.    }
  189. }
  190. /*****************************************************************************************************************************/
  191.  
  192. void special(int chipset)
  193. /* chipset specific settings, like memory speed and the likes */
  194. {
  195.    int tmp;  
  196.  
  197.    PDEBUG(("Setting chipset-specific special registers\n"));
  198.    switch(chipset)
  199.    {
  200.      case CS_ATI    : ATI_PUTEXTREG(0xB0, ATI_GETEXTREG(0xb0) & ~0x08);   /* (for 188xx chips) Enable 8 CRT accesses for each CPU access */
  201.                       break;
  202.      case CS_S3     : /* set `M-parameter' which controls the DRAM FIFO balancing */
  203.                       /* this was derived from the svgalib 1.2.8 code */
  204.                       tmp = Inb_CRTC(0x54) & 0x07;
  205.                       if (OFLG_ISSET(OPT_XFAST_DRAM)) Outb_CRTC(0x54,tmp | (0 << 3));
  206.                       if (OFLG_ISSET(OPT_FAST_DRAM))  Outb_CRTC(0x54,tmp | (2 << 3));
  207.                       if (OFLG_ISSET(OPT_MED_DRAM))   Outb_CRTC(0x54,tmp | (10 << 3));
  208.                       if (OFLG_ISSET(OPT_SLOW_DRAM))  Outb_CRTC(0x54,tmp | (20 << 3));
  209.                       break;
  210.     default: PDEBUG(("SPECIAL VGA chip settings: no special settings for chipset #%d\n",chipset));
  211.    }
  212. }
  213. /*****************************************************************************************************************************/
  214.  
  215. void interlace(int chipset, t_mode *m)
  216. /*
  217.  * chipset specific interlace settings (also used to un-set interlace mode)
  218.  * some chipsets need to change some timings for interlacing (e.g. dividing V-timings by 2).
  219.  */
  220. {
  221.    int il = MOFLG_ISSET(m, ATTR_INTERLACE);
  222.    
  223.    PDEBUG(("%sing interlacing mode\n", il ? "Sett" : "Disabl"));
  224.    switch(chipset)
  225.    {
  226.      case CS_S3    : Outbit_CRTC(0x42, 5, il ? 1 : 0);
  227.                      if (il)
  228.                      {
  229.                        m->VDisplay /= 2;
  230.                        m->VSyncStart /= 2;
  231.                        m->VSyncEnd /= 2;
  232.                        m->VTotal /= 2;
  233.                        m->VBlankStart /= 2;
  234.                        m->VBlankEnd /= 2;
  235.                        Outb_CRTC(0x3C, m->HDisplay/2);
  236.                      }
  237.                      break;
  238.      default: if (il) PDEBUG(("INTERLACING not supported yet on chipset #%d\n",chipset));
  239.    }
  240. }
  241. /*****************************************************************************************************************************/
  242.  
  243. #define HSTEXT_MINCLOCK 36000
  244.  
  245. void S3_StartHSText_FontLoad(int pixclock, int do_it)
  246. {
  247.    bool hstext = OFLG_ISSET(OPT_S3_HS_TEXT) && (pixclock > HSTEXT_MINCLOCK);
  248.    bool old_was_HS=(Inb_CRTC(0x31) & 0x40);
  249.  
  250.    PDEBUG(("Current S3 text mode: %s\n", old_was_HS ? "High Speed" : "Normal" ));
  251.  
  252.    if ( hstext && (!old_was_HS) && !OFLG_ISSET(OPT_LOADFONT) )
  253.    {
  254.       PWARNING(("\n\
  255.        Switching from normal to High Speed text mode requires the Option `LoadFont'.\n\
  256.        Normal text mode will be used until font loading is enabled.\n"));
  257.       hstext=FALSE;
  258.    }
  259.    
  260.    if ( (!hstext) && old_was_HS && !OFLG_ISSET(OPT_LOADFONT) )
  261.    {
  262.       PWARNING(("\n\
  263.        Switching from High Speed to normal text mode requires the Option `LoadFont'.\n\
  264.        High speed text mode will be used until font loading is enabled.\n"));
  265.       hstext=TRUE;
  266.    }
  267.    
  268.    if (do_it)
  269.    {
  270.      Outbit_CRTC(0x3A, 5, 0);   /* normal font store mode, just for sure... */
  271.      if (hstext)
  272.        {
  273.          Outbit_CRTC(0x3A, 5, 1);   /* prepare S3 for high speed font store mode */
  274.          Outbit_CRTC(0x31, 6, 1);   /* enable high speed font fetch mode */
  275.        }
  276.        else
  277.        { 
  278.          Outbit_CRTC(0x31, 6, 0);   /* disable high speed font fetch mode */
  279.        }
  280.    }
  281. }
  282.  
  283. /*****************************************************************************************************************************/
  284.  
  285. void set_V_timings(int active, int start_sync, int stop_sync, int total)
  286. {
  287.   int vbs, vbe;
  288.   if (total > 1023)
  289.   {
  290.     /* round UP around sync to avoid null sync width */
  291.     active = active / 2;
  292.     start_sync = start_sync / 2;
  293.     stop_sync = (stop_sync + 1) / 2;
  294.     total = (total + 1) / 2;
  295.     Outbit_CRTC(0x17, 2, 1);  /* Vertical total double mode */
  296.   }
  297.   else Outbit_CRTC(0x17, 2, 0);
  298.   Set_VERT_TOTAL(total);
  299.   Set_VDISPL_END(active);
  300.   Set_VRETRACE_START(start_sync); Set_VRETRACE_END(stop_sync);
  301.   /* set 8 lines of overscan, the rest is blanking (if the sync doesn't come too close) */
  302.   vbs = MIN(start_sync, active+8);
  303.   vbe = MAX(stop_sync, total-8);
  304.   if ((vbe-vbs)>=127)
  305.    {
  306.      PDEBUG(("V Blanking size >= 127 ; setting to 127\n"));
  307.      vbe = vbs+127;
  308.    }
  309.   Set_VBLANK_START(vbs); Set_VBLANK_END(vbe);
  310. }
  311.  
  312. void set_H_timings(int active, int start_sync, int stop_sync, int total)
  313. {
  314.   int hrs=start_sync/8;
  315.   int hre=stop_sync/8;
  316.   int hde=(active/8) & 0xFFFFFFFE;
  317.   int htot=total/8;
  318.  
  319.   /* set 1 char of overscan, with the rest blanked (if sync positions don't overlap) */
  320.   int hbs=MIN(hrs, hde+1);
  321.   int hbe=MAX(hre, htot-1);
  322.   if ((hbe-hbs)>=63)
  323.    {
  324.      PDEBUG(("H Blanking size >= 63 ; setting to 63\n"));
  325.      hbe = hbs+63;
  326.    }
  327.   Set_HOR_TOTAL(htot);
  328.   Set_HOR_DISPL_END(hde);
  329.   Set_HSYNC_START(hrs); Set_HSYNC_END(hre);
  330.   Set_LOG_SCREEN_WIDTH(hde);
  331.   Set_HBLANK_START(hbs); Set_HBLANK_END(hbe);
  332. }
  333.  
  334. int set_charwidth(int width)
  335. {
  336.    switch(width)
  337.    {
  338.       case 8: Outbit_SEQ(1, 0, 1);
  339.               SET_PIXELPAN(0);
  340.               break;
  341.       case 9: Outbit_SEQ(1, 0, 0);
  342.               SET_PIXELPAN(8);
  343.               break;
  344.       default: return(1);
  345.    }
  346.    return(0);
  347. }
  348.  
  349. /*****************************************************************************************************************************/
  350. /* "get" functions: used for getting certain parameters from the chips (for grabmode etc.) */
  351.  
  352. inline int get_charwidth()
  353. {
  354.   return((Inb_SEQ(1) & 0x01) ? 8 : 9);
  355. }
  356.  
  357.  
  358. inline int Get_VERT_TOTAL()
  359. {
  360.   return( (Inb_CRTC(0x6) + ((Inb_CRTC(0x7) & 0x01) ? 256 : 0) + ((Inb_CRTC(0x7) & 0x20) ? 512 : 0)) + 2);
  361. }
  362.  
  363.  
  364. inline int Get_HOR_TOTAL()
  365. {
  366.   return(Inb_CRTC(0)+5);
  367. }
  368.  
  369.  
  370. inline int Get_HOR_DISPL_END()
  371. {
  372.   return((int)Inb_CRTC(1)+1);
  373. }
  374.  
  375. /* calculate end value from start value and mask. this is because "end" values in VGA regs define only the few
  376.  * last bits of the entire value. See VGA data for more */
  377.  
  378. #define ENDCALC(start,end,mask) ( ((((start & mask) > end) ? (start + (mask+1)) : start) & ~mask) | end  )
  379.  
  380. inline int Get_HSYNC_START()
  381. {
  382.   return((int)Inb_CRTC(4));
  383. }
  384.  
  385. inline int Get_HSYNC_END()
  386. {
  387.   int start, end;
  388.   start = Get_HSYNC_START();
  389.   end = Inb_CRTC(5) & 0x1f;
  390.   return(ENDCALC(start, end, 0x1f));
  391. }
  392.  
  393. inline int Get_HBLANK_START()
  394. {
  395.   return((int)Inb_CRTC(2) + 1);
  396. }
  397.  
  398. inline int Get_HBLANK_END()
  399. {
  400.   /* this does not work correctly when Get_HOR_TOTAL() reads wrapped data (as in 2048+ pixel wide modes) */
  401.   int start, end, htot, endblk;
  402.   htot = Get_HOR_TOTAL();
  403.   start = Get_HBLANK_START();
  404.   end = ((int)Inb_CRTC(3) & 0x1F) + ((Inb_CRTC(5) & 0x80) ? 0x20 : 0);
  405.   endblk = ENDCALC(start, end, 0x3f)+1;
  406.   return((endblk < htot) ? endblk : (end+1));
  407. }
  408.  
  409. inline int Get_VBLANK_START()
  410. {
  411.   return((int)Inb_CRTC(0x15) + ((Inb_CRTC(0x7) & 0x08) ? 256 : 0) + ((Inb_CRTC(0x9) & 0x20) ? 512 : 0));
  412. }
  413.  
  414. inline int Get_VBLANK_END()
  415. {
  416.   int start = Get_VBLANK_START()-1;
  417.   int end = Inb_CRTC(0x16);
  418.   return(ENDCALC(start, end, 0xff));
  419. }
  420.  
  421.  
  422. inline int Get_VERT_DISPL_END()
  423. {
  424.   return( ( (int)Inb_CRTC(0x12) + ((Inb_CRTC(0x7) & 0x02) ? 256 : 0) + ((Inb_CRTC(0x7) & 0x40) ? 512 : 0) ) +1);
  425. }
  426.  
  427. inline int Get_VRETRACE_START()
  428. {
  429.   int vrs = (int)Inb_CRTC(0x10) + ((Inb_CRTC(0x7) & 0x04) ? 256 : 0) + ((Inb_CRTC(0x7) & 0x80) ? 512 : 0);
  430.   return( (vrs==0) ? 1024 : vrs );
  431. }
  432.  
  433. inline int Get_VRETRACE_END()
  434. {
  435.   int start, end;
  436.   start = Get_VRETRACE_START();
  437.   end = Inb_CRTC(0x11) & 0x0f;
  438.   return(ENDCALC(start, end, 0x0f));
  439. }
  440.  
  441. inline int Get_MAX_SCANLINE()
  442. {
  443.   return((Inb_CRTC(0x9) & 0x1f) +1);
  444. }
  445.  
  446. inline int Get_HSYNC_POLARITY()
  447. {
  448.   return( (inb(VGA_MISC_R) & 0x40) ? NEG : POS);
  449. }
  450.  
  451. inline int Get_VSYNC_POLARITY()
  452. {
  453.   return( (inb(VGA_MISC_R) & 0x80) ? NEG : POS);
  454. }
  455.  
  456. inline int Get_TX_GR_Mode()
  457. /* returns 0 for text mode, 1 for graphics mode */
  458. {
  459.   return(Inb_GR_CTL(6) & 0x01);
  460. }
  461.  
  462.